import requests
from urllib import parse
import time
import json
import urllib3
import random

urllib3.disable_warnings()


class TooLongExceptin(Exception):
    def __str__(self):
        print("461异常")

class XHS660(object):
    def __init__(self):
        # self.proxies = { "http": "http://192.168.100.9:8888"}
        self.proxies = None
        self.ENCRYPT_URL = "http://120.53.131.28:18283/690"
        self.TOKEN = "5e7c58a4d651d470c080b27a61320148"
        self.USER_AGENT = "Dalvik/2.1.0 (Linux; U; Android 5.0.2; Samsung Note3 Build/LMY47X) Resolution/1080*1920 Version/6.90.0 Build/6900179 Device/(samsung;Samsung Note3)"
        self.deviceId = ''
        self.fid = ''
        self.device_fingerprint = ''
        self.sid = ''
        self.xy_ter_str = ''

        self.query_params = {
        }
        self.error_count = 0

    def huakuai(self):
        url = self.ENCRYPT_URL + '/rid?token=' + self.TOKEN
        ret = requests.get(url, data=data, proxies=self.proxies)
        print('ret -->', ret.json())

        xhs_url = "https://www.xiaohongshu.com/api/sns/v1/system_service/slide_captcha_check"


    # 写入注册用户数据
    def set_register_user_data(self, user_data):
        self.deviceId = user_data['device_id']
        self.device_fingerprint = user_data['smid']
        self.sid = user_data['sid']
        self.fid = user_data['fid']
        self.query_params = {
            "deviceId": self.deviceId,
            "device_fingerprint": self.device_fingerprint,
            "device_fingerprint1": self.device_fingerprint,
            "fid": self.fid,
            "lang": "zh",
            "platform": "android",
            "sid": self.sid,
            "t": int(time.time())
        }
        self.xy_ter_str = self.__get_ter_str()
        # self.__crypt_method = user_data['crypt_method']

    # 获取注册用户数据
    def get_register_user_data(self):
        return {
            'device_id': self.deviceId,
            'smid': self.device_fingerprint,
            'sid': self.sid,
            'fid': self.fid,
            # 'crypt_method': self.__crypt_method,
        }
    def __get_ter_str(self):
        """
        deviceId=353CE2F-0131-474E-A093-DF39D12E4515&device_fingerprint=202006261454019d1b1a0db8172b59cbe25925c1c3900001ab4b27b14c4883&device_fingerprint1=202006261454019d1b1a0db8172b59cbe25925c1c3900001ab4b27b14c4883&
        fid=1595172589-0-0-2de0b0d2666328142e712e63c19fad35
        &lang=zh&platform=android&sid=session.1593665994331207470119&sign=b1c352302484d97e6e9c93f7334a2720&t=1592222248
        :return:
        """
        url = "https://www.xiaohongshu.com/api/sns/v3/user/me?"
        query_params = {
            "deviceId": self.deviceId,
            "device_fingerprint": self.device_fingerprint,
            "device_fingerprint1": self.device_fingerprint,
            "fid": self.fid,
            "lang": "zh",
            "platform": "android",
            "sid": self.sid,
            "t": int(time.time())
        }
        url = self.__append_url_params(url, query_params)

        header = {
            "User-Agent": self.USER_AGENT,
            "xy-common-params": self.__get_xy_common_params(),
            "xy-platform-info": self.__get_xy_platform_info(),
            "shield": ""
        }

        response = requests.get(url, headers=header, proxies=self.proxies, verify=False)
        # print(response.headers)
        # print(response.headers)
        xy_ter_str = response.headers["xy-ter-str"]
        return xy_ter_str
    def __get_xy_common_params(self):
        return "platform=android&deviceId={deviceId}&version=6.90&build=6900179&t={t}&identifier_flag=1&fid={fid}&device_fingerprint={device_fingerprint}&sid={sid}".format(
            deviceId=self.deviceId,
            fid=self.fid,
            device_fingerprint=self.device_fingerprint,
            sid=self.sid,
            t=int(time.time())
        )
    def __get_xy_platform_info(self):
        return "platform=android&version=6.90&build=6900179&deviceId={deviceId}&bundle=com.xingin.discover".format(
            deviceId=self.deviceId,
        )
    def __append_url_params(self, url, query_params):
        params = parse.urlencode(query_params)
        if not url.__contains__('?'):
            url = url + '?'

        if url.endswith('?') or url.endswith('&'):
            url = url + params
        else:
            url = url + '&' + params
        return url

    def __http_get(self, url, query_params):
        # print('url -->', url)
        xy_common_params = self.__get_xy_common_params()
        xy_platform_info = self.__get_xy_platform_info()
        url = self.__append_url_params(url, query_params)
        url = self.__append_url_params(url, self.query_params)
        data = {
            "token": self.TOKEN,
            "url": url,
            "xy-common-params": xy_common_params,
            "xy-platform-info": xy_platform_info,
            "xy-ter-str": self.xy_ter_str,
            "body": ""  # GET 请求不需要 body 参数
        }
        # print('data -->', json.dumps(data))

        # ret = requests.post(self.ENCRYPT_URL, data=data, proxies=self.proxies).json()
        # print('url -->', url)
        # print('ret -->', ret)
        # if ret["code"] == 1000:
        if 1:
            header = {
                "User-Agent": self.USER_AGENT,
                "xy-common-params": xy_common_params,
                "xy-platform-info": xy_platform_info,
                # "shield": ret["data"]["shield"]
                "shield": ""
            }
            result = requests.get(url, headers=header, proxies=self.proxies, verify=False)
            # print('result -->', result.text)
            print('status_code -->', result.status_code)
            # if result.status_code == 461:
                # result = self.test_post_rid()
                # print("重新请求")
                # return self.__http_get(url, query_params)
            # print('result.text -->', result.text)

            # result_dict = json.loads(result.text)
            # if 'msg' in result_dict and result_dict['msg'] == "" and result_dict["result"] == 0 and result_dict["success"]:
            # if result_dict == {'msg': '', 'result': 0, 'success': True}:
            #     self.error_count += 1
            #     if self.error_count > 20:
            #         exit("出现机器人验证")
            #     else:
            #         time.sleep(random.randint(10, 20))
            # else:
            #     self.error_count = 0
            return result.text
        else:
            print(json.dumps(ret, ensure_ascii=False))

    def test_post_rid(self):

        url = "http://120.53.131.28:18283/rid?token=" + self.TOKEN
        print('url -->', url)
        ret = requests.get(url, proxies=self.proxies, verify=False).json()
        print(json.dumps(ret, ensure_ascii=False))

        rid = ret["data"]["rid"]
        print('rid -->', rid)

        url = "https://www.xiaohongshu.com/api/sns/v1/system_service/slide_captcha_check"
        xy_common_params = self.__get_xy_common_params()
        xy_platform_info = self.__get_xy_platform_info()

        # xy_platform_info = "platform=android&build=6300132&deviceId={deviceId}".format(deviceId=self.deviceId)
        # xy_common_params = "platform=android&deviceId={deviceId}&device_fingerprint={device_fingerprint}&device_fingerprint1={device_fingerprint}&versionName=6.90.0&channel=Store360&sid={sid}&t={t}&uis=light&identifier_flag=2".format(
        #     deviceId=self.deviceId,
        #     device_fingerprint=self.device_fingerprint,
        #     sid=self.sid,
        #     t=int(time.time()),
        # )

        body = "from=native&pass=true&rid={rid}&deviceId={deviceId}&identifier_flag=0&device_fingerprint1={device_fingerprint}&uis=light&device_fingerprint={device_fingerprint}&versionName=6.90.0&platform=android&sid={sid}&t={t}&x_trace_page_current=login_full_screen_pwd_page&lang=zh-Hans&channel=BaiduPinzhuan".format(
            rid=rid,
            deviceId=self.deviceId,
            device_fingerprint=self.device_fingerprint,
            sid=self.sid,
            t=int(time.time()),
        )
        # print('body -->', body)
        data = {
            "url": url,
            "token": self.TOKEN,
            "xy-platform-info": xy_platform_info,
            "xy-common-params": xy_common_params,
            "xy-ter-str": self.xy_ter_str,
            "body": body
        }
        ret = requests.post(self.ENCRYPT_URL, data=data, proxies=self.proxies).json()
        # ret = requests.post(url, data=data, proxies=self.proxies).json()
        # print('ret -->', ret)
        if ret["code"] == 1000:
        # if 1:
            header = {
                "User-Agent": self.USER_AGENT,
                "xy-platform-info": xy_platform_info,
                "xy-common-params": xy_common_params,
                "shield": ret["data"]["shield"],
                "content-type": "application/x-www-form-urlencoded"
            }

            # body = ret["data"]["body"]
            ret = requests.post(url, data=body, headers=header, proxies=self.proxies, verify=False)

            print(ret.text)
            return ret


        else:
            print(json.dumps(ret, ensure_ascii=False))


    # 获取主页地址
    def get_home_feed(self):
        url = "https://www.xiaohongshu.com/api/sns/v6/homefeed"
        query_params = {
            "oid": "homefeed_recommend"
        }
        return self.__http_get(url, query_params)

    def get_message(self, blogger_id):
        xhs_url = 'https://www.xiaohongshu.com/api/im/messages/history'
        query_params = {
            'limit': 20,
            'chat_user_id': blogger_id,
            'last_id': 0,
            'start_id': 0,
        }
        return self.__http_get(xhs_url, query_params)

    # 获取博主用户信息
    def get_user_info(self, user_id):
        query_params = {
            'user_id': user_id,
            'identifier_flag': 2,
            'uis': 'light',
            'x_trace_page_current': 'user_page'
        }
        url = 'https://edith.xiaohongshu.com/api/sns/v3/user/info?'
        return self.__http_get(url, query_params)

    # 获取用户首页笔记
    def get_user_home_note(self, user_id, cursor=None):
        """
        获取用户首页笔记(跟PC端看到的一致)
        :param user_id:     博主id
        :param cursor:      接上一页最后一条的笔记id
        :return:
        """
        xhs_url = 'https://edith.xiaohongshu.com/api/sns/v4/note/user/posted'
        query_params = {
            'user_id': user_id,
            'num': 10,  # 获取数量
            'cursor': cursor,
            'use_cursor': True,
            'identifier_flag': 2,
            'uis': 'light',
        }
        return self.__http_get(xhs_url, query_params)

    # 获取用户收藏的笔记
    def get_user_faved_note(self, user_id, cursor=None):
        """
        获取用户收藏的笔记
        :param user_id:     博主id
        :param cursor:      接上一页最后一条的笔记id
        :return:
        """
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v1/note/{user_id}/faved'.format(user_id=user_id)
        query_params = {
            'num': 10,  # 获取数量
            'offset': cursor,
            'identifier_flag': 2,
            'uis': 'light',
        }
        return self.__http_get(xhs_url, query_params)

    # 获取用户笔记
    def get_user_note(self, user_id, cursor=None, note_type=""):
        """
        获取用户笔记
        :param user_id:     博主id
        :param cursor:      接上一页最后一条的笔记id
        :param note_type:   笔记类型， 为空获取图文， special.video 获取视频
        :return:
        """
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v3/note/user/' + user_id
        query_params = {
            'user_id': user_id,
            'num': 10,      # 获取数量
            'cursor': cursor,
            'sub_tag_id': note_type
        }
        return self.__http_get(xhs_url, query_params)

    # 根据关键词获取用户列表
    def get_user_list(self, keyword, page=1):
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v3/search/user'
        query_params = {
            'keyword': keyword,
            'page': page,
            'page_size': 20,  # 获取数量
        }
        return self.__http_get(xhs_url, query_params)

    # 获取note评论
    def get_note_comments(self, note_id, start=''):
        """获取note评论
        :param note_id: note id
        :param start: 评论id，首页不传，下一页传上一页最后一个评论id
        :return:
        """
        xhs_url = 'https://edith.xiaohongshu.com/api/sns/v5/note/comment/list?'
        query_params = {
            'note_id': note_id,
            'start': start,
            'num': 20,
            'show_priority_sub_comments': 0,
            'source': 'explore',
            'top_comment_id': '',
            'identifier_flag': 2,
            'uis': 'light',
            # 'x_trace_page_current': 'video_feed'
        }
        return self.__http_get(xhs_url, query_params)

    # 获取note子级评论
    def get_note_sub_comments(self, note_id, comment_id, start):
        """获取note子级评论
        :param note_id: note id
        :param comment_id: 父级评论id
        :param start: 评论id，上一页最后一个同级别评论id
        :return:
        """
        xhs_url = 'https://edith.xiaohongshu.com/api/sns/v2/note/comment/sub_comments?'
        query_params = {
            'note_id': note_id,
            'comment_id': comment_id,
            'start': start,
            'num': 5,
            'source': '',
            'filter_sub_comment_id': '',
            'identifier_flag': 2,
            'uis': 'light',
        }
        return self.__http_get(xhs_url, query_params)

    # 获取note评论
    def get_message(self, chat_user_id):
        """获取note评论
        :param chat_user_id: 用户id
        :return:
        """
        xhs_url = 'https://www.xiaohongshu.com/api/im/messages/history'
        query_params = {
            'chat_user_id': chat_user_id,
            'limit': 20,
            'last_id': 0,
            'start_id': 0,
            'identifier_flag': 2,
            'uis': 'light',
        }
        return self.__http_get(xhs_url, query_params)

    # def post_note_comments(self, note_id, comment_id, content):
    #     """回复note评论
    #     :param note_id: note id
    #     :param comment_id: 评论id
    #     :return:
    #     """
    #     xhs_url = 'https://edith.xiaohongshu.com/api/sns/v4/note/comment'
    #     form_params = {
    #         'content': content,
    #         'note_id': note_id,
    #         'comment_id': comment_id,
    #         'at_users': "[]",
    #         'hash_tags': "",
    #         'is_note_first_comment': False,
    #         'identifier_flag': 2,
    #         'uis': 'light'
    #     }
    #     return self.__http_post(xhs_url, form_params)

    # 获取用户视频
    def get_user_videos(self, user_id, page, page_size):
        """获取用户视频
        :param user_id: user id
        :param page: 页码
        :param page_size: 每次返回的条数
        :return:
        """
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v3/note/user/' + user_id
        query_params = {
            'page': str(page),
            'page_size': str(page_size),
            'sub_tag_id': 'special.video'
        }
        return self.__http_get(xhs_url, query_params)

    # 获取用户关注的用户列表
    def get_user_followings(self, user_id, start=''):
        """获取用户关注的用户列表
        :param user_id: user id
        :param start: 关注列表中的用户id，首页不传，下一页传上一页最后一个用户id
        :return:
        """
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v1/user/' + user_id + '/followings?'
        query_params = {
            'start': start
        }
        return self.__http_get(xhs_url, query_params)

    # 获取用户粉丝
    def get_user_followers(self, user_id, start=''):
        """获取用户粉丝
        :param user_id: user id
        :param start: 粉丝列表中的用户id，首页不传，下一页传上一页最后一个用户id
        :return:
        """
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v1/user/' + user_id + '/followers?'
        query_params = {
            'start': start
        }
        return self.__http_get(xhs_url, query_params)

    # 获取笔记分类
    def get_note_class(self, note_id):
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v1/note/dislike_callback_info'
        query_params = {
            'note_id': note_id,
            'source': 'explore',
            'ads_track_id': '',
            'identifier_flag': 2,
            'uis': 'light',
        }
        return self.__http_get(xhs_url, query_params)

    # 搜索关键词
    def search(self, keyword, page, page_size, sort=''):
        """搜索
        :param keyword: 关键词
        :param page: 页码，最小1
        :param page_size: 每次返回的条数
        :param sort: '' --> 综合  'popularity_descending' --> 最热    'time_descending' --> 最新

        :return:
        """
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v10/search/notes?'
        query_params = {
            'keyword': keyword,
            'filters': [],
            'sort': sort,
            'page': str(page),
            'page_size': str(page_size),
            'source': 'explore_feed',
            'search_id': '',
            'api_extra': '',
            'page_pos': str(page_size * (page - 1)),
            'allow_rewrite': '1',
            'geo': '',
            'word_request_id': ''
        }
        return self.__http_get(xhs_url, query_params)

    # 查询下拉
    def search_xiala(self, keyword):
    #
        """搜索
        :param keyword: 关键词
        :param page: 页码，最小1
        :param page_size: 每次返回的条数
        :param sort: '' --> 综合  'popularity_descending' --> 最热    'time_descending' --> 最新

        :return:
        """
        xhs_url = 'https://edith.xiaohongshu.com/api/sns/v4/search/recommend?'
        query_params = {
            'keyword': keyword,
            'source': 'search_result_notes',
            'word_request_id': '',
            'identifier_flag': 2,
            'uis': 'light',
        }
        return self.__http_get(xhs_url, query_params)

    # 获取话题相关的日记
    def get_topic_notes(self, topic_id, page, page_size):
        """获取话题相关的日记
        :param topic_id: 话题id
        :param page: 页码
        :param page_size: 每次返回的条数
        :return:
        """
        # https://www.xiaohongshu.com/fe_api/burdock/v2/page/5af15997ec9d1350b50e924f/notes?page=1&pageSize=6&sort=hot&sid=session.1590715307675120159053
        """
        sort: hot --> 最热   time --> 最新
        """
        xhs_url = 'https://www.xiaohongshu.com/fe_api/burdock/v2/page/' + topic_id + "/notes?"
        query_params = {
            'page': str(page),
            'pageSize': str(page_size)
        }
        return self.__http_get(xhs_url, query_params)

    # 获取话题参与人数和浏览次数
    def get_topic(self, topic_id):
        """获取话题参与人数和浏览次数
        :param topic_id: 话题id
        :return:
        """
        # https://www.xiaohongshu.com/fe_api/burdock/v2/page/topic/5af15997ec9d1350b50e924f?sid=session.1590715307675120159053
        # xhs_url = 'https://www.xiaohongshu.com/fe_api/burdock/v2/page/topic/' + topic_id + "?"
        # xhs_url = 'https://www.xiaohongshu.com/api/sns/v1/page/' + topic_id + "/header?"
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v2/page/topic'
        # print('xhs_url -->', xhs_url)
        query_params = {
            'page_id': topic_id
        }
        return self.__http_get(xhs_url, query_params)

    # 获取视频笔记详情
    def get_video_detail(self, user_id, note_id):
        """获取视频笔记详情
        :param user_id: 用户id
        :param note_id: note id
        :return:
        """
        xhs_url = 'https://www.xiaohongshu.com/api/sns/v1/note/user/' + user_id + '/videofeed'
        query_params = {
            'source_note_id': str(note_id),
            'cursor_score': '',
            'num': '5',
            'source': 'posted'
        }
        return self.__http_get(xhs_url, query_params)

    # 获取笔记详情
    def get_note_detail(self, note_id):
        """获取笔记详情
        :param note_id:
        :return:
        """
        # xhs_url = 'https://www.xiaohongshu.com/api/sns/v1/note/feed'
        xhs_url = 'https://edith.xiaohongshu.com/api/sns/v1/note/feed'
        query_params = {
            # 'note_id_list': str(note_id),
            # 'source_note_id': str(note_id)
            'note_id': str(note_id),
            'page': 1,
            'num': 5,
            'fetch_mode': 1,
            'source': 'explore'
        }
        return self.__http_get(xhs_url, query_params)

    # 根据关键词获取商品列表
    def get_products_list(self, keyword, page=1):
        xhs_url = 'https://www.xiaohongshu.com/api/store/ps/products/v3'
        query_params = {
            'keyword': keyword,
            'page': page,
            'size': 20,  # 获取数量
            'source': "store_feed",
            'page_pos': 0,
            "uis": "light"
        }
        return self.__http_get(xhs_url, query_params)

if __name__ == '__main__':
    # data = {"device_id": "33a75df8-7735-40b9-ad83-0c4b5204f983", "smid": "20201121113734ed0e7f3041b289f97ba4ba6376e3d8df0165a1bf53e5974e", "sid": "session.1605929860888759168854", "fid": "160592984810f87a262027e6d3308945f95d89d22c93", "crypt_method": "486587f16affb0e9", "register_time": "1605929860"}
    data = {"device_id": "fadc8fef-b692-386f-b877-7184ab99fd2d", "smid": "2021101817302847b673196a986af9d973c30818bf7ea300779987618a7d97", "device_fingerprint1": "20211018173029d96e168168278f553007f7848f5e8a1b5191f509441737a4", "device_fingerprint": "2021101817302847b673196a986af9d973c30818bf7ea300779987618a7d97", "sid": "session.1634552409861562971488", "fid": "163454942910f47bf65b0164d22407f769870abdc8fc", "xy_ter_str": "rj+nHk+e5ctWsdWBhOuJ/xchIffIJXZyfrePSGc4NZI2uYQfjJ49X2fZgWFmwRy6jnLqGLL9vRFoCavF1VCcfOxtu8H6SHnBIaI9mi+vOudYutQJdZI2wHrH8+Sg3Z1m", "register_time": "2021-09-21 08:40:16", "machine_num": "1634549436485"}
    obj = XHS660()
    obj.set_register_user_data(data)

    ret = obj.get_message("5e48dc0400000000010006b5")
    print(ret)
    exit()
    # obj.get_home_feed()
    # result = obj.get_user_info("5d3c00950000000012004e73")
    result = obj.get_home_feed()
    # result = obj.get_user_info("5d3c00950000000012004e73")
    print('result -->', result)
    print(json.loads(result)['data'])
    # obj.get_user_list("装修")